package com.up.interview.redis.xianliu;

import java.util.TreeSet;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.TimeUnit;

/**
 * @author: liuchengjun
 * @title: SlidingWindowRateLimit
 * @projectName: 海联技术中台V2.0
 * @depart 软件事业部
 * @description:
 * @date: 2025/10/21/周二 15:36 (星期二)
 * @since V2.0
 */
public class SlidingWindowRateLimit extends BaseRateLimit {

    /**
     * 滑动窗口限流算法
     *
     * ● 窗口大小  1s
     * ● 最大阀值  100
     * ● 当前时间：请求的时间
     * ● 开始时间：请求的时间 - 窗口时间
     *
     * 移除开始时间前的数据，并统计当前容量
     * 实现思路：使用ms级时间戳，便于操作
     * redis zset
     * ● 有序，不允许数据重复
     * ● merber 成员  score排序字段
     * @return
     */
    //调表实现线程安全的有序集合
    private final ConcurrentSkipListSet<Long> concurrentSkipListSet = new ConcurrentSkipListSet<>();

    @Override
    protected boolean acquire() {
        Long startTime = System.currentTimeMillis() - calTime();
        //移除窗口外的旧请求（滑动窗口）
        concurrentSkipListSet.removeIf(timestamp -> timestamp < startTime);
        if(concurrentSkipListSet.size() <= rateLimitConfig.getPermitsPer()){
            concurrentSkipListSet.add(startTime);
            return true;
        }
        return false;
    }

    public Long calTime(){
        long windowSize = rateLimitConfig.getWindowSize();
        TimeUnit timeUnit = rateLimitConfig.getTimeUnit();
        return timeUnit.toMillis(windowSize);
    }

    @Override
    public long availablePermits() {
        return concurrentSkipListSet.size() - rateLimitConfig.getPermitsPer();
    }
}
